﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;

namespace AppToolkit.WPF.UI
{
    /// <summary>
    /// Interface for Error Dialog.
    /// </summary>
    public interface IErrorReportDialog
    {
        /// <summary>
        /// Exception to be visualized.
        /// </summary>
        Exception Exception { get; set; }

        /// <summary>
        /// Set to true, in case the user has choosen to ignore the displayed error.
        /// </summary>
        bool IgnoreError { get; }

        /// <summary>
        /// Allows setting the owning window.
        /// </summary>
        Window Owner { get; set; }

        /// <summary>
        /// Displays the error dialog as a modal window.
        /// </summary>
        /// <returns></returns>
        bool? ShowDialog();
    }

    /// <summary>
    /// Interaction logic for ErrorReportDialog.xaml
    /// </summary>
    public sealed partial class ErrorReportDialog : Window, IErrorReportDialog
    {
        private Exception _exception;

        /// <summary>
        /// default CTOR 
        /// </summary>
        public ErrorReportDialog()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Exception to be visualized.
        /// </summary>
        public Exception Exception
        {
            get { return _exception; }
            set
            {
                _exception = value;
                this.CurrentException = _exception;
            }
        }

        /// <summary>
        /// Set to true, in case the user has choosen to ignore the displayed error.
        /// </summary>
        public bool IgnoreError { get; private set; }

        private Exception CurrentException
        {
            get { return (Exception)GetValue(CurrentExceptionProperty); }
            set { SetValue(CurrentExceptionProperty, value); }
        }

        /// <summary>
        /// Using a DependencyProperty as the backing store for CurrentException.  This enables animation, styling, binding, etc...
        /// </summary>
        static readonly DependencyProperty CurrentExceptionProperty =
            DependencyProperty.Register("CurrentException", typeof(Exception), typeof(ErrorReportDialog), new UIPropertyMetadata(null));

        #region Internals
        private void OnBtnIgnoreClick(object sender, RoutedEventArgs e)
        {
            this.IgnoreError = true;
            this.Close();
        }

        private void OnBtnAbortClick(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
        #endregion

        #region CommandHandler
        private void OnNavigateBack(object sender, ExecutedRoutedEventArgs e)
        {
            Exception current = _exception;
            while (current.InnerException != this.CurrentException)
            {
                current = current.InnerException;
            }
            this.CurrentException = current;
        }

        private void OnCanNavigateBack(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.CurrentException != null)
            {
                e.CanExecute = this.CurrentException != _exception;
            }
        }

        private void OnNavigateForeward(object sender, ExecutedRoutedEventArgs e)
        {
            this.CurrentException = this.CurrentException.InnerException;
        }

        private void OnCanNavigateForeward(object sender, CanExecuteRoutedEventArgs e)
        {
            if (this.CurrentException != null)
            {
                e.CanExecute = this.CurrentException.InnerException != null;
            }
        }

        private void OnCopy(object sender, ExecutedRoutedEventArgs e)
        {
            Clipboard.SetText(this.Exception.ToString());
        }

        private void OnSaveAs(object sender, ExecutedRoutedEventArgs e)
        {
            var dlg = new Microsoft.Win32.SaveFileDialog();
            dlg.OverwritePrompt = true;
            dlg.DefaultExt = "*.txt";

            if (dlg.ShowDialog() ?? false)
            {
                //TODO: Formatierung des Exception Stacks verbessern
                using (var strm = this.StorageProvider.GetStoreStream(dlg.FileName))
                using (var wri = new StreamWriter(strm))
                {
                    wri.WriteLine(this.Exception.ToString());
                }
            }
        }
        #endregion

        #region For testability reasons
        private IStorageProvider _storageProvider;

        internal IStorageProvider StorageProvider
        {
            get
            {
                if (_storageProvider == null)
                {
                    _storageProvider = new FileStorageProvider();
                }
                return _storageProvider;
            }
            set { _storageProvider = value; }
        } 
        #endregion
    }
}
